#include "stdafx.h"

#include "boundary_building.h"

namespace blue_sky{

	template <class strategy_t>
	void build_boundary<strategy_t>::set_matrix(sp_csr_matrix_t  geom_matrix, 
		int number_of_cells, index_point3d_t dimens){				
		i_vector_type col_ind = geom_matrix->get_cols_ind();
		i_vector_type row_ptr = geom_matrix->get_rows_ptr();
		fp_vector_type values = geom_matrix->get_values();
		size_t size = (size_t) geom_matrix->get_n_non_zeros();
		this->dimens = dimens;		
		this->number_of_cells = number_of_cells;

		geom_factors.resize(number_of_cells * 4);

		for(int i = 0; i < number_of_cells; i++){
			bool bx_1, bx_2, by_1, by_2;
			bx_1 = bx_2 = by_1 = by_2 = true;
			i_vector_type current_cols;
			for(size_t j = 0; j < size; j++){
				if (col_ind[j] == i){
					current_cols.push_back(j);
				}				
			}		

			for(int j = 0; j < (int) current_cols.size(); j++){
				size_t cell = current_cols[j];
				item_t value = fabs(values[cell]);
				if(col_ind[cell + 1] == i+1){
					geom_factors[i * 4 + X2] = value;
					bx_2 = false;
				} else if(cell - 1 >= 0 && col_ind[cell - 1] == i - 1){
					geom_factors[i * 4 + X1] = value;
					bx_1 = false;
				} else if(col_ind[cell + 1] > i+1){
					geom_factors[i * 4 + Y2] = value;
					by_2 = false;
				}else if(cell - 1 >= 0 && col_ind[cell - 1] < i - 1){
					geom_factors[i * 4 + Y1] = value;
					by_1 = false;
				}
			}

			if (bx_1){
				result[X1]->push_back(i);
			} 
			if (bx_2){
				result[X2]->push_back(i);
			}

			if(dimens[1] > 1){
				if (by_1){
					result[Y1]->push_back(i);
				}
				if (by_2){
					result[Y2]->push_back(i);
				}
			}

			bool is_boundary = false;
			if(dimens[1] == 1){
				is_boundary = bx_1 || bx_2;
			} else {
				is_boundary = bx_1 || bx_2 || by_1 || by_2;			
			}			

			if (is_boundary){
				boundary_cells.push_back(i);
			} else{
				non_boundary_cells.push_back(i);
			}			
		}
		fill_boundary_geom();
	}

	template<class strategy_t>
	void 
	build_boundary<strategy_t>::fill_boundary_geom ()
	{
		typename i_vector_type::iterator it;

		i_vector_type boundary = *get_result_map()[X1];
		for(it = boundary.begin(); it < boundary.end(); ++it){
			i_type cell = *it;
			geom_factors[cell * 4 + X1] = geom_factors[cell * 4 + X2];
		}

		boundary = *get_result_map()[X2];
		for(it = boundary.begin(); it < boundary.end(); ++it){
			i_type cell = *it;
			geom_factors[cell * 4 + X2] = geom_factors[cell * 4 + X1];
		}

		boundary = *get_result_map()[Y1];
		for(it = boundary.begin(); it < boundary.end(); ++it){
			i_type cell = *it;
			geom_factors[cell * 4 + Y1] = geom_factors[cell * 4 + Y2];
		}

		boundary = *get_result_map()[Y2];
		for(it = boundary.begin(); it < boundary.end(); ++it){
			i_type cell = *it;
			geom_factors[cell * 4 + Y2] = geom_factors[cell * 4 + Y1];
		}
	}

	template<class strategy_t>
	build_boundary<strategy_t>::build_boundary (bs_type_ctor_param param)
	{
		result.insert( std::pair<coords, i_vector_type*>(X1,new i_vector_type()));
		result.insert( std::pair<coords, i_vector_type*>(X2,new i_vector_type()));
		result.insert( std::pair<coords, i_vector_type*>(Y1,new i_vector_type()));
		result.insert( std::pair<coords, i_vector_type*>(Y2,new i_vector_type()));
	}

	template<class strategy_t>
	std::map<coords, typename strategy_t::csr_matrix_t::i_vector_type*> 
	build_boundary<strategy_t>::get_result_map()
	{
		return result;
	}

	template<class strategy_t>
	typename strategy_t::csr_matrix_t::i_vector_type 
	build_boundary<strategy_t>::get_boundary_cells()
	{
		return boundary_cells;
	}

	template<class strategy_t>
	typename strategy_t::csr_matrix_t::i_vector_type 
	build_boundary<strategy_t>::get_non_boundary_cells()
	{
		return non_boundary_cells;
	}

	/**
	* \brief  copy-ctor for calc_model
	* \param  src calc_model instance
	* */
	template <class strategy_t>
	build_boundary<strategy_t>::build_boundary (const this_t & src)
		: bs_refcounter (src), bs_node(src)
	{
		if (&src != this)
			*this = src;
	}

	//Copy and create constructors for Blue-Sky system
	BLUE_SKY_TYPE_STD_CREATE_T_DEF(build_boundary, (class));
	BLUE_SKY_TYPE_STD_COPY_T_DEF(build_boundary, (class));

	//Import of class to the Blue-Sky system
	BLUE_SKY_TYPE_IMPL_T_EXT(1, (build_boundary<base_strategy_fi>) , 1, 
		(objbase), "boundary_builder_fi", "boundary_builder-int", 
		"boundary_builder with float items and integer indexes", false);
	BLUE_SKY_TYPE_IMPL_T_EXT(1, (build_boundary<base_strategy_di>) , 1, 
		(objbase), "boundary_builder_di", "boundary_builder-int", 
		"boundary_builder with double items and integer indexes", false);
	BLUE_SKY_TYPE_IMPL_T_EXT(1, (build_boundary<base_strategy_mixi>) , 1, 
		(objbase), "boundary_builder_mixi", "boundary_builder-mixi",
		"boundary_builder mixi", false);
}